{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MNIST"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import torch\n",
    "\n",
    "# 导入数据集\n",
    "from torchvision.datasets import mnist\n",
    "\n",
    "# 导入预处理\n",
    "import torchvision.transforms as transforms\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "# 导入nn及优化器\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "\n",
    "from torch import nn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 超参数\n",
    "\n",
    "train_batch_size = 64\n",
    "test_batch_size = 128\n",
    "learning_rate = 0.01\n",
    "num_epoches = 20\n",
    "lr = 0.01\n",
    "momentum = 0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 预处理\n",
    "\n",
    "transform = transforms.Compose(   # 将多个转化函数拼接在一起，将图片的两个通道，按照均值0.5进行normalize\n",
    "    [transforms.ToTensor(), transforms.Normalize([0.5], [0.5])]\n",
    ")\n",
    "\n",
    "train_dataset = mnist.MNIST(\"../../data/pymnist\", train = True, transform=transform, download = False)\n",
    "test_dataset = mnist.MNIST(\"../../data/pymnist\", train = False, transform=transform, download = False)\n",
    "\n",
    "train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)\n",
    "test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 可视化数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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uZxKqQYNGpQ3jq8+fOWVV3p9yblxpMN3vvOdqH322Wd7fePHj692OjriiCO8uFOnTlG7RYsWXh/XUOpD8vb0u+++u+DXPv/881HbORcsp9A4QwEABEFBAQAEQUEBAARhxczHmVnNJ+9mzpwZtS+66CKvr5xrKF988UXU3rx5s9fXtm3bgvfTpEmTknMolXPOqn7QItRi3HTu3NmL58yZE7Xj77XkP7pA+vr7XwnxfCSpd+/eUTv+2AVJWrduXaXSWOSc61GpnYeQhs+cUHr08H/U77zzTs5td+3a5cVNmzatSE5l2OfY4QwFABAEBQUAEETqbxs+77zzvPjUU0+N2skprmKmvJJPPZs1a1bU3rRpk9f33e9+14vz3e73gx/8IGpPnDix4HwQ1j333OPF8eVMLrzwQq+vGlNcknTkkUdG7eS4DnXLO9Jr8ODBBW8b/zxqTDhDAQAEQUEBAARBQQEABJG6ayjt2rXz4hdffNGLjzrqqIL3FV8iZcqUKV7f/fff78Vbt24taD+SNGLEiKidfEpkfBmP5s2be33xp65J0s6dO3MeE8UZMmSIFyeXqF+2bFnUXrhwYVVySopfe0teM4nfRrxx48YqZYRqSj4WI27Hjh1eXMyyLGnCGQoAIAgKCgAgCAoKACCI1F1DiT+qVSrumsncuXO9eNiwYVF7/fr1JeeUvIby4IMPRu2HH37Y64svPZ5cFn369OlevHz58pJzgm/o0KFenFwCfsKECdVMR9LXrwdeddVVUXv37t1e37hx46I219bqQ69evfLGcclHFLz33nuVSKniOEMBAARBQQEABJG6Ka9iJG//vO6667y4nGmufOJTV/FpDEnq2bNnRY6JrzvssMOi9llnnZV321osgxO/vVzyp2+XLFni9c2ePbsqOaF6ivksqJdlmjhDAQAEQUEBAARBQQEABJH6aygHHJC75n3729+uYiZfMfvqAYnJ/PLle99993nx97///aB57W+aNWsWtY8//niv74UXXqh2Ol/ToUOHnH0ffPBBFTNBLSSf0JgUX2KHaygAAMRQUAAAQVBQAABBpO4ayo033ujFaXw06oABA6J2t27dvL54vsnck9dQUJ4vv/wyaieXqujSpYsXxx+/u2HDhorkc/TRR3txckn9uDfffLMiOaC2evfuHbWHDx+ed9v4o8Y/+eSTiuVUTZyhAACCoKAAAIJI3ZRXfDqpVpJPYezUqZMX33XXXQXtZ926dV7MKrJhbdu2LWonV24ePHiwF7/66qtRO7lCdDE6d+7sxe3bt4/aydWFnXM595PGqVyUr1WrVlE7358QSNIbb7xR6XSqjjMUAEAQFBQAQBAUFABAEKm7hpIGd999txffdNNNBb92xYoVUfvqq6/2+latWlVWXsjt3nvv9eL48jiSdMkll0TtcpZlST4SIX6dpJiniz7zzDMl54D0ynereHypFUl68sknK5xN9XGGAgAIgoICAAiCggIACIJrKFkzZ86M2qeeemrJ+/njH/8YtVleo3qWLl3qxVdccYUXd+3aNWp37Nix5ONMnjw5Z9+zzz7rxcnHQ8fF/4YGjdcJJ5zgxfmWW0kur5J8hHk94AwFABAEBQUAEETqprySt3vmW77goosuyruvp556Kmofd9xxebeNH6ecZTHSsHQMvi6+GnFyZeJQPv7444K3TS7hwhMcG6devXp5cb7Pq2nTplU4m9rjDAUAEAQFBQAQBAUFABBE6q6hTJw40YvHjx+fc9tXXnnFi/Nd+yjmukgx2z7xxBMFb4v6lrz+l4zjuGZSH+LL1Scll+l59NFHK51OzXGGAgAIgoICAAgidVNeU6dO9eLRo0d7cfJpipWQfNLikiVLvHjEiBFRe82aNRXPB41D8gmN+Z7YiPrQr1+/nH3J1cU3bdpU6XRqjjMUAEAQFBQAQBAUFABAEKm7hrJy5UovHjZsmBcPHDgwat96660VyeGBBx7w4scff7wix0F9ad68ed5+Vhhu/Jo2berFHTp0yLnt9u3bvXjnzp0VySlNOEMBAARBQQEABEFBAQAEkbprKEnz5s3LGc+aNcvri/99iOQvJT99+nSvL760veQvkxF/6iJQqGuvvdaLN27c6MU/+clPqpgNKiG5LFPyqYvxxxIsW7asKjmlCWcoAIAgKCgAgCBSP+WVz2uvvZY3BqrpnXfe8eKHH37Yi2fPnl3NdFABu3fv9uK7777bi+PL7SxatKgqOaUJZygAgCAoKACAICgoAIAgrJglts2M9bhTyDmX+9GAKcC4Sa1FzrketU4iH8ZOau1z7HCGAgAIgoICAAiCggIACIKCAgAIgoICAAiCggIACIKCAgAIgoICAAiCggIACIKCAgAIotjl69dLWlmJRFCytrVOoACMm3Ri7KBU+xw7Ra3lBQBALkx5AQCCoKAAAIKgoAAAgqCgAACCoKAAAIKgoAAAgqCgAACCoKAAAIKgoAAAgvj/0kJqQVDkEVUAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "for batch_idx, (example_data, example_targets) in enumerate(test_loader):\n",
    "    fig = plt.figure()\n",
    "    for i in range(6):\n",
    "        plt.subplot(2, 3, i+1)\n",
    "        plt.tight_layout()\n",
    "        plt.imshow(example_data[i][0], cmap=\"gray\", interpolation=\"none\")\n",
    "        plt.title(f\"Ground Truth: {example_targets[i]}\")\n",
    "        plt.xticks([])\n",
    "        plt.yticks([])\n",
    "    break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Net(nn.Module):\n",
    "    \n",
    "    def __init__(self,  in_dim, n_hidden_1, n_hidden_2, out_dim):\n",
    "        u\"\"\"\n",
    "        设计三层隐藏网络\n",
    "        使用sequential构建网络\n",
    "        \"\"\"\n",
    "        super(Net, self).__init__()\n",
    "        \n",
    "        # 第一层线性\n",
    "        self.layer1 = nn.Sequential(\n",
    "            nn.Linear(in_dim, n_hidden_1),\n",
    "            nn.BatchNorm1d(n_hidden_1)\n",
    "        )\n",
    "        \n",
    "        # 第二层\n",
    "        self.layer2 = nn.Sequential(\n",
    "            nn.Linear(n_hidden_1, n_hidden_2),\n",
    "            nn.BatchNorm1d(n_hidden_2)\n",
    "        )\n",
    "        \n",
    "        # 第三层\n",
    "        self.layer3 = nn.Sequential(\n",
    "            nn.Linear(n_hidden_2, out_dim),\n",
    "        )\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = F.relu(self.layer1(x))\n",
    "        x = F.relu(self.layer2(x))\n",
    "        x = self.layer3(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 实例化网络"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 检测GPU\n",
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "# init model based  on normalized image size\n",
    "model = Net(28 * 28,  300, 100, 10)\n",
    "model.to(device)\n",
    "\n",
    "# 定义损失函数和优化器\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.SGD(model.parameters(), lr = lr, momentum=momentum)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 0, Train Loss: 0.5470, Train Acc: 0.8909, Test Loss: 0.5063, Test Acc: 0.9061\n",
      "epoch: 1, Train Loss: 0.5473, Train Acc: 0.8915, Test Loss: 0.5036, Test Acc: 0.9038\n",
      "epoch: 2, Train Loss: 0.5479, Train Acc: 0.8911, Test Loss: 0.5068, Test Acc: 0.9054\n",
      "epoch: 3, Train Loss: 0.5466, Train Acc: 0.8909, Test Loss: 0.5021, Test Acc: 0.9055\n",
      "epoch: 4, Train Loss: 0.5476, Train Acc: 0.8917, Test Loss: 0.5064, Test Acc: 0.9024\n",
      "epoch: 5, Train Loss: 0.5476, Train Acc: 0.8914, Test Loss: 0.5044, Test Acc: 0.9036\n",
      "epoch: 6, Train Loss: 0.5485, Train Acc: 0.8908, Test Loss: 0.5065, Test Acc: 0.9046\n",
      "epoch: 7, Train Loss: 0.5480, Train Acc: 0.8915, Test Loss: 0.5061, Test Acc: 0.9031\n",
      "epoch: 8, Train Loss: 0.5471, Train Acc: 0.8915, Test Loss: 0.5015, Test Acc: 0.9044\n",
      "epoch: 9, Train Loss: 0.5472, Train Acc: 0.8917, Test Loss: 0.5094, Test Acc: 0.9049\n",
      "epoch: 10, Train Loss: 0.5469, Train Acc: 0.8917, Test Loss: 0.5056, Test Acc: 0.9062\n",
      "epoch: 11, Train Loss: 0.5477, Train Acc: 0.8916, Test Loss: 0.5033, Test Acc: 0.9047\n",
      "epoch: 12, Train Loss: 0.5466, Train Acc: 0.8921, Test Loss: 0.5094, Test Acc: 0.9040\n",
      "epoch: 13, Train Loss: 0.5487, Train Acc: 0.8908, Test Loss: 0.5025, Test Acc: 0.9046\n",
      "epoch: 14, Train Loss: 0.5474, Train Acc: 0.8921, Test Loss: 0.4981, Test Acc: 0.9033\n",
      "epoch: 15, Train Loss: 0.5481, Train Acc: 0.8907, Test Loss: 0.5031, Test Acc: 0.9055\n",
      "epoch: 16, Train Loss: 0.5482, Train Acc: 0.8914, Test Loss: 0.5065, Test Acc: 0.9037\n",
      "epoch: 17, Train Loss: 0.5477, Train Acc: 0.8919, Test Loss: 0.5086, Test Acc: 0.9034\n",
      "epoch: 18, Train Loss: 0.5481, Train Acc: 0.8914, Test Loss: 0.5042, Test Acc: 0.9051\n",
      "epoch: 19, Train Loss: 0.5460, Train Acc: 0.8926, Test Loss: 0.5098, Test Acc: 0.9054\n"
     ]
    }
   ],
   "source": [
    "losses, acces, eval_losses, eval_acces = [], [], [], []\n",
    "\n",
    "for epoch in range(num_epoches):\n",
    "    train_loss = 0\n",
    "    train_acc = 0\n",
    "    model.train()\n",
    "    \n",
    "    # 动态修改参数学习率\n",
    "    if epoch % 5 == 0:\n",
    "        optimizer.param_groups[0][\"lr\"] *= 0.1\n",
    "    \n",
    "    for img, label in train_loader:\n",
    "        img = img.to(device)\n",
    "        label = label.to(device)\n",
    "        \n",
    "        img = img.view(img.size(0), -1)\n",
    "        \n",
    "        # 向前传播\n",
    "        out = model(img)\n",
    "        loss = criterion(out, label)\n",
    "        \n",
    "        # 反向传播\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        \n",
    "        # 记录误差\n",
    "        train_loss += loss.item()\n",
    "        \n",
    "        # 计算分类的准确率\n",
    "        _, pred = out.max(1)\n",
    "        num_correct = (pred == label).sum().item()\n",
    "        acc = num_correct / img.shape[0]\n",
    "        train_acc += acc\n",
    "    \n",
    "    losses.append(train_loss / len(train_loader))\n",
    "    acces.append(train_acc / len(train_loader))\n",
    "    \n",
    "    # 在测试集上检验效果\n",
    "    eval_loss = 0\n",
    "    eval_acc = 0\n",
    "    \n",
    "    # 改为预测模式\n",
    "    model.eval()\n",
    "    for img, label in test_loader:\n",
    "        img = img.to(device)\n",
    "        label = label.to(device)\n",
    "        img = img.view(img.size(0), -1)\n",
    "        \n",
    "        out = model(img)\n",
    "        loss  = criterion(out, label)\n",
    "        \n",
    "        # 记录误差\n",
    "        eval_loss += loss.item()\n",
    "        \n",
    "        # 记录准确率\n",
    "        _, pred = out.max(1)\n",
    "        num_correct = (pred == label).sum().item()\n",
    "        acc = num_correct / img.shape[0]\n",
    "        eval_acc += acc\n",
    "        \n",
    "    eval_losses.append(eval_loss / len(test_loader))\n",
    "    eval_acces.append(eval_acc / len(test_loader))\n",
    "    \n",
    "    print(\"epoch: {}, Train Loss: {:.4f}, Train Acc: {:.4f}, Test Loss: {:.4f}, Test Acc: {:.4f}\".format(\n",
    "        epoch, \n",
    "        train_loss / len(train_loader), \n",
    "        train_acc / len(train_loader), \n",
    "        eval_losses[-1], \n",
    "        eval_acces[-1]\n",
    "    ))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7f7cd44e5640>"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYcAAAEICAYAAAC0+DhzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAABHDklEQVR4nO3de3zcVZ34/9c712mTmaS5TdImkJYmpReS3hGQ+x3dooAIskJF1lW3i6yyLKyrP8V1V3fXdb3tIiKCl69yFUErBZRyUWmbNr2l17Rpc2knSXOZ3JrLZM7vj5lJp8kkmSRzTd7PxyOPzuUzn8/JNMl7zjnv9zlijEEppZTylxDtBiillIo9GhyUUkqNoMFBKaXUCBoclFJKjaDBQSml1AgaHJRSSo2gwUGpKRCRx0TkS0Ee+5SI/Gu426RUKCRFuwFKRZOIHAPuM8a8MZnXG2M+HdoWKRUbtOeg1ChERD88qRlLg4OasUTkZ8A5wCsi0iUiD4mIEZFPikgt8Efvcc+JiENEnCLytogs9TvH0FCRiFwhIvUi8gURaRKRkyLyiTGu/zciUi0irSLysojM9T4uIvJt7zk6RGSPiCzzPneTiOwTkU4RaRCRB8P4FqkZTIODmrGMMR8HaoG/MsakA896n7ocWAxc773/e6AEyAN2AL8Y47T5QAYwD/gk8AMRmTP8IBG5Cvh34HagADgO/Mr79HXAZUCp91y3Ay3e534M/K0xxgoswxvAlAo17TYrNdJXjDHdvjvGmCd9t0XkK0CbiGQYY5wBXjsAPGqMcQEbRaQLWAS8N+y4u4AnjTE7vOd9xHveYu85rMD5wFZjzP5h518iIruMMW1A29S+VaUC056DUiPV+W6ISKKIfENEjohIB3DM+1TOKK9t8QYGnx4gPcBxc/H0FgAwxnTh6R3MM8b8Efg+8AOgSUQeFxGb99BbgZuA4yLylohcNPFvT6nxaXBQM12gZYn9H/sYcDNwDZ4hnmLv4zLF654AzvXdEZE0IBtoADDGfNcYswpYgmd46R+9j28zxtyMZ4jrJc4MhSkVUhoc1EzXCCwY43kr0IfnU/1s4N9CdN1fAp8QkeUikuo97xZjzDERWSMiF4pIMtAN9AJuEUkRkbu8Q1oDQAfgDlF7lDqLBgc10/078C8i0g7cFuD5n+IZ/mkA9jFy7mBSvHUVXwJeAE4C5wF3eJ+2AT/CM59wHE9g+k/vcx8HjnmHuD6NZ+5CqZAT3exHKaXUcNpzUEopNYIGB6WUUiNocFBKKTWCBgellFIjTIsK6ZycHFNcXBztZiilVFzZvn37KWNMbqDnpkVwKC4upqKiItrNUEqpuCIix0d7ToeVlFJKjaDBQSml1AgaHJRSSo0wLeYclFLTy8DAAPX19fT29ka7KdOCxWKhsLCQ5OTkoF+jwUEpFXPq6+uxWq0UFxcjMtUFcGc2YwwtLS3U19czf/78oF+nw0pKqZjT29tLdna2BoYQEBGys7Mn3AvT4KCUikkaGEJnMu+lBgel1KS43YZnttXS5xqMdlNUGGhwUEpNyvbaNv7phT1sqmqMdlNCrqWlheXLl7N8+XLy8/OZN2/e0P3+/v4xX1tRUcH9998/oesVFxdz6tSpqTQ55HRCWik1KSfaTwNwyNEJ5VFuTIhlZ2ezc+dOAL7yla+Qnp7Ogw8+OPS8y+UiKSnwn8/Vq1ezevXqSDQzrLTnoJSalMYOzwTnwcbOKLckMtavX8+nP/1pLrzwQh566CG2bt3KRRddxIoVK7j44os5ePAgAJs3b+aDH/wg4Aks9957L1dccQULFizgu9/9btDXO3bsGFdddRVlZWVcffXV1NbWAvDcc8+xbNkyysvLueyyywCoqqpi7dq1LF++nLKyMg4fPjzl71d7DkqpSTnp9ASHQ2EODl99pYp9JzpCes4lc238f3+1dMKvq6+v589//jOJiYl0dHTwzjvvkJSUxBtvvME///M/88ILL4x4zYEDB3jzzTfp7Oxk0aJFfOYznwmq3uDv//7vueeee7jnnnt48sknuf/++3nppZd49NFH2bRpE/PmzaO9vR2Axx57jM997nPcdddd9Pf3Mzg49XkgDQ5KqUnx9RxqW3vo6XcxO2X6/zn5yEc+QmJiIgBOp5N77rmHw4cPIyIMDAwEfM0HPvABUlNTSU1NJS8vj8bGRgoLC8e91l/+8hdefPFFAD7+8Y/z0EMPAXDJJZewfv16br/9dm655RYALrroIr7+9a9TX1/PLbfcQklJyZS/1+n/v6mUCguHs5cEAbeB6qYuygozw3KdyXzCD5e0tLSh21/60pe48sor+fWvf82xY8e44oorAr4mNTV16HZiYiIul2tKbXjsscfYsmULv/vd71i1ahXbt2/nYx/7GBdeeCG/+93vuOmmm/jhD3/IVVddNaXr6JyDUmpSGjv6KC/KBOCgY2bMO/hzOp3MmzcPgKeeeirk57/44ov51a9+BcAvfvELLr30UgCOHDnChRdeyKOPPkpubi51dXUcPXqUBQsWcP/993PzzTeze/fuKV9fg4NSasLcbkNjRy9ri7NITUoI+7xDLHrooYd45JFHWLFixZR7AwBlZWUUFhZSWFjI5z//eb73ve/xk5/8hLKyMn72s5/xne98B4B//Md/5IILLmDZsmVcfPHFlJeX8+yzz7Js2TKWL1/O3r17ufvuu6fcHjHGTPkk0bZ69Wqjm/0oFTnNnX2s+fobfHXdUp7bXkdWWio/vXdtyM6/f/9+Fi9eHLLzqcDvqYhsN8YEzLvVnoOKmsONnXz8x1to7xm7qEjFHoc3U8lus1Bqt3pqHdS0ElRwEJEbROSgiFSLyMMBnl8vIs0istP7dd+w520iUi8i3/d77E4R2SMiu0XkVRHJ8T7+FRFp8DvXTVP9JlVsemXXCd45fIpfVzZEuylqghzeTKWCDAuL7FYcHb04ewJn66j4NG5wEJFE4AfAjcAS4E4RWRLg0GeMMcu9X08Me+5rwNt+50wCvgNcaYwpA3YDG/yO/7bfuTZO7FtS8WJLTSsAz2+vj3JL1ET5gkN+hoXSfCsAh5pC23uYDkPesWIy72UwPYe1QLUx5qgxph/4FXBzsBcQkVWAHXjN/2HvV5p4lgu0ASeCbrWKe32uQSrr2slJT6HqREfIi5xUeDU6e0lMEHLSU1lk9wSHUGYsWSwWWlpaNECEgG8/B4vFMqHXBVPnMA+o87tfD1wY4LhbReQy4BDwD8aYOhFJAL4F/DVwjV9jB0TkM8AeoBs4DPyd37k2iMjdQAXwBWNM2/CLicingE8BnHPOOUF8GyqW7K530u9y89D15/MvL+3l+e31fHluoA6pikWOjl5y01NJTBAKMixYU5NCmrFUWFhIfX09zc3NITvnTObbCW4iQlUE9wrwS2NMn4j8LfA0cBXwWWCjMabefz1xEUkGPgOsAI4C3wMeAf4V+D88w1DG+++3gHuHX9AY8zjwOHiylUL0fagI2eodUrp2iZ3Nh5p4aWcDD994PilJmiMRDxzOXuwZnk+iIkJpvjWkPYfk5OQJ7VqmQi+Y38QGoMjvfqH3sSHGmBZjTJ/37hPAKu/ti/D0Ao4B/wXcLSLfAJZ7X3fEePqNzwIXex9rNMYMGmPcwI/wDGupaWZLTSuL7FbmpKVw26pCWrv7efNgU7SbpYLk6OilwHZmmKLUbuVQY6cOA00jwQSHbUCJiMwXkRTgDuBl/wNEpMDv7jpgP4Ax5i5jzDnGmGLgQeCnxpiH8QSXJSKS633Ntb7XDDvXh4G9E/6uVExzDbrZfqyVtfOzALisJJec9FSdmI4jjc5e8jPOBIdF9nTaegZo7uob41Uqnow7rGSMcYnIBmATkAg8aYypEpFHgQpjzMvA/SKyDnABrcD6cc55QkS+CrwtIgPAcb/X/IeILMczrHQM+NtJfF8qhu072UF3/+BQcEhKTOCWlfN48t0aTnX1kZOeOs4ZVDR197no7HNh9+85+DKWHF3kWSc28aliU1BzDt500o3DHvuy3+1H8MwZjHWOp4Cn/O4/BjwW4LiPB9MmFb988w2+4ABw26pCHn/7KC9VNnDfpQui1TQVhDNprGeC+FDGUmMn7y/JiUq7VGjp7J+KuK01rRRnzz77k6fdSnlhBs9vr9dx6xjX6Fcd7ZOdnkpOeopWSk8jGhxURLndhm1+8w3+bltVyAFHJ1Va8xDTfJv85NvOHj4qtVtnzK5wM4EGBxVR1c1dtPUMsKZ4ZHBYVz6PlMQEnZiOcf7V0f5K7VYON3bidmvPbzrQ4KAiyrdkxoXzs0c8lzE7mWuX2vnNzgb6Xe5IN00FqbGjF5slacTOb4vyrXT3D9LQfjpKLVOhpMFBRdTWmlbybRaKsmYFfP62VYW09QzwxwONEW6ZCpZjWBqrT6k9HQj/ntIqMjQ4qIgxxrC1poW187Pwr5j3d1lJLnab1jzEssaO3rMmo31K/DKWVPzT4KAipra1h8aOvoCT0T6JCcKHVxTy5sFmmjp7I9g6FSxHR++IyWgAmyWZuRkWzViaJjQ4qIg5M98wenAAz9DSoNvwm0pdqDfWuAbdNHf2BRxWAk8x3MHGrgi3SoWDBgcVMVtrWslKS2FhXvqYxy3MS2fFOZla8xCDmrv6cJuRmUo+i+xWjjR14RrUhIJ4p8FBRczWmlbWFM8Zdb7B322rCjnY2MmeBmcEWqaC5RilxsGn1G6lf9DNsZaeSDZLhYEGBxURDmcvta09rA2QwhrIB8vmkpqkNQ+xprFjZHW0v0W+NZZ0UjruaXBQEbH1WHDzDT4Zs5K5fmk+v9l5gj7XYDibpiZgqOcwyrDSwrx0REK7K5yKDg0OKiK21rSQnprE4gJb0K+5bVUhztMDvLFP93mIFSc7eklOFLJmpwR83pKcSHF2mvYcpgENDioitta0surcOSQmjD/f4HPJwhwKMiw8v71u/INVRDQ6PTUOCWP8P5ba0+Oi1qHf5eb1fY3aMx2FBgcVdq3d/Rxq7BqzviGQxAThlpXzeOtQM00dWvMQC0arcfC3yG7l2Kluegdi94/uX460cNN33+FvflrBk+8ei3ZzYpIGBxV22yY43+Dv1pWFuA38urJh/INV2DV29A3tHT2a0nwrbgNHmmOv3uFUVx+ff3Ynd/7oPfpcg5yXm8ZzFXWaMh2ABgcVdltrWklNSuCCwowJv3ZBbjqrzp3Dc1rzEHXGGM+6SkH0HCC2MpbcbsP/21LL1d96i1d2nWDDlQt57YHL+dvLz+PoqW4qjrdFu4kxR4ODCrutNa2sOCeT1KTESb3+I6sKqW7qYle91jxEU0evi9MDg+MGh+KcNJIThYOO2Og57DvRwa2P/Zl//vUeFhdY+f3nLuXB6xcxKyWRD1xQQFpKIs9s03mt4TQ4qLDq7B2g6oQz6PqGQG4qK8CSnKAT01HmS2Mdb1gpOTGB83LTo95z6Opz8a+/3cdfff9dalt6+O/by/nl37yPhXnWoWPSUpP4q/K5/G73STp7B6LY2tijwUGF1fbjbbjN5OYbfGyWZG5Yms/LO0/E9CTndOfb5KdgnOAA3l3holTrYIzh1b0nufa/3+LHf6rho2uK+OMXruCWlYUBq/NvX1PE6YFBfrv7ZBRaG7s0OKiw2lrTSlKCsOKczCmd5yOri+jodfH6Pt3nIVoax1k6w9+ifCsN7acj/mm8rrWHTz5dwad/voPM2Sm88JmL+bcPX0DG7ORRX7OiKJOFeek6tDSMBgcVVltrWrmgMGPErmETddGCbOZmWHQ5jSjy9RzybKnjHlvqnZQ+3BSZeYd+l5sfvFnNtd9+iy1HW/iXDyzmlQ2XsPKcOeO+VkT46Ooidta1R30oLJZocFBh0zswyK769gnXNwSSkCDcuqqQdw43D419q8hydPSSlZYSVGLBUMZSBIaW3jvqqVn4z00HuXJRHm984XLuu3QBSYnB/3n78Mp5JCUIz2rvYYgGBxU2O+vaGRg0rC2eenAAz3IabgMvVmrvIRp81dHBKJwzi1nJiWGtlHYNunno+V3c8binZuEn69fwf3+9ioKMwFvQjiUnPZVrFtt5sTKy+5dXN3UxEKPLm2twUGGztaYVEVh9bmiCw7nZaawtztJ9HqLkpLOX/CCGlMDT0yu1hzdjafPBZp6tqOfeS+bz2gOXc+X5eVM63+1rCmnt7ucP+yMzr7X9eBvX/Pdb/HZ3bG5qpcFBhc3WmlbOz7eNORk4UbetKuRoczc7attDdk4VnMaOXvIn8Knck7EUvjmHV6sc2CxJPHzj+cxKmVwNjT/f/uXPVkRmaOm/Xz8IwPEY3ftCg4MKi4FBN9uPt00phTWQm8oKmJWcqBPTEdbnGqSluz+oTCWfRflWTnX10dLVF/L2uAbdvLG/kasX20lJCs2fsaTEBG5bVchbh8I/r/Xe0Rb+VN0CnNkjI9ZocFBhsbfByemBwZBMRvtLT03ixgvy+e0urXmIpKYOzx/4/IzghpXgTMbSoTDsKb21ppX2ngGuX5of0vPevroItyGsBZfGGP779UPkWVM5LzeNxo7QB89QCCo4iMgNInJQRKpF5OEAz68XkWYR2en9um/Y8zYRqReR7/s9dqeI7BGR3SLyqojkeB/PEpHXReSw99/xc9FUzNla41lsb02IJqP93baqkM4+F5uqHCE/twpsvB3gAgnnrnCbqhxYkhO4vDQ3pOc9NzuN9y3I4tmKetzu8Mxr/am6ha01rfzdlQs5NzstZrPvxg0OIpII/AC4EVgC3CkiSwIc+owxZrn364lhz30NeNvvnEnAd4ArjTFlwG5gg/fph4E/GGNKgD9476s4s7WmlQW5aeRag/+kGaz3zc+mcM4sHVqKoJPj7AAXSJ41lYxZySHPWHK7DZuqGrm8NDckcw3D3b66iNrWHt6raQn5uT29hoMUZFi4Y20RdpuFps44DQ7AWqDaGHPUGNMP/Aq4OdgLiMgqwA685v+w9ytNPPXsNsA3ZX8z8LT39tPAh4K9looNg27D1mOtIZ9v8ElIEG5dWci71ac40X46LNdQZ/P1HApswU9IiwiL7NaQ1zrsqm/H0dEb8iElnxuXFWBNTeK5itB/+Nh8qJkdte1suGohqUmJ2G2pnOrqj2j6bLCCCQ7zAP8BuHrvY8Pd6h0iel5EigBEJAH4FvCg/4HGmAHgM8AePEFhCfBj79N2Y4xvkRMHnsAygoh8SkQqRKSiubk5iG9DRcpBRyedva6Qzzf4u21VIUb3eYgYh7MXS3ICtlkTq3QvzffsChfK1ONNVY0kJQhXnx/wT8OUzUpJZN3yuWzccxLn6dAt/2GM4duvH6Jwziw+sqoIOLMUSSz2HkI1If0KUOwdInqdM5/8PwtsNMacFYJFJBlPcFgBzMUzrPTI8JMaz09UwJ8qY8zjxpjVxpjVubmhHXdUU7PV2x2fykqs4ynKms37FmTpRi0R4tsBLtDCdWNZZLfS2esaWnpjqowxbKpycNF52SFNkR7uo2uK6HO5eXlX6GoQ3tjfxO56J/dfXTKUYeWbw4nFSelggkMDUOR3v9D72BBjTIsxxvfdPQGs8t6+CNggIseA/wLuFpFvAMu9rzviDQDPAhd7X9MoIgUA3n91d/k4s/VYK/MyZzEvc+KVqhNxy8pCjrX0sLehI6zXUZ5hpYlMRvv4MpZCtULr4aYuak51h21IyeeCeRmcn28N2XIabrcnQ6k4eza3rDgz8HImOMRnz2EbUCIi80UkBbgDeNn/AN8fc691wH4AY8xdxphzjDHFeIaWfmqMeRhPcFkiIr6P/Nf6XuM99z3e2/cAv5nwd6WixhjD1pq2sA4p+fgyVbaEYeJQnc3R0TuhyWif0hDvCvfqXgcicN2S8Awp+YgIt68uYk+Dk30npv7h49UqB/tPdvC5a0rOWvPJ957GZXAwxrjwZBJtwvMH/FljTJWIPCoi67yH3S8iVSKyC7gfWD/OOU8AXwXeFpHdeHoS/+Z9+hvAtSJyGLjGe1/FiZpT3Zzq6otIcLDbLBRnzx5Km1XhYYyh0dk3oQI4nzlpKeRZU0NWKb2pysHKc+aQN4m2TNSHV8wjJTFhyhXTg27PXMN5uWmsKz97unbO7GRSEhNCNuwWSkHNLhljNgIbhz32Zb/bjxBgzmDY8U8BT/ndfwx4LMBxLcDVwbRLxR7fH+pIBAffdV7f14jbbUhImNh4uApOa3c//YPuSfUcwFPvEIqeQ11rD1UnOvjiTYunfK5gzElL4dqldl7a2cAjN50/6W1uf7v7BIebuvjenStIHPYzKiLk2VKHigxjiVZIR9FJ52l+9PbRaTWhurWmlZz0FBbkpEXkemvnZ9PWM0B1c2zsVzwd+T7VTqbnAJ6hpcNNnQxOsajMV/QY7vkGfx9dXUR7zwCvVU1uMT7XoJvvvHGY8/OtfOCCgoDH2G2WmCyE0+AQRd/7YzVf37ifmlPd0W5KyGypaWXt/KwJZ7VMlq+WYstRnXcIl6Hq6Mn2HOxWegfc1LVObYG5TVUOFhfYOCd79pTOMxGXLMxhXuasSQ8t/WbnCY6e6uaBa0pH7dnm2yw0TuNUVjVBvQOD/NabJhep3bLCrb6th4b20yHbvyEYhXNmUZBhYYvOO4SNw+ldV2myPQfvMhpTqZRu7uyj4ngbN0Sw1wCQ6N1k6t3qU9S3TSy4DQy6+c4fDrN0ro3rl44+gZ5nSx3agjWWaHCIkjcPNNHR6wLg8DTZmnDbMd98Q/jqG4YTEdbOz2JrTeu0Gp6LJY6OXkSY9FIoJXnpwNR2hXt9XyPGwPXLwpulFMhHVhUCTHi5lhd31FPb2sPnry0dsyedb7PQ3T8Y8f22x6PBIUpe2NGA3ZbK3AxLWFatjIatNa3YLElDC65Fytr5WTR19sXsuvjxzuE8TU56KskT2HbTX1pqEkVZs6bUc3i1ykFx9uyh7UcjqShrNpecl8NzE1iMr9/l5rt/qKa8KJOrxtmEKFYL4TQ4REFLVx+bDzbxoeXzWJRvnTbDSltqWllTnDUiIyPcfPMOmtIaHo6OPgomOd/gs8g++Ywl5+kB/lx9iuuX5kdsLmu429cU0dB+mj8dORXU8c9U1NHQfnrcXgPEbiGcBocoeGXXCVxuwy0rCymxWznS3DXlTI5oa+7s42hzN2silMLq77zcdLLSUnTeIUwmsnf0aErtVo42d09qgbk3DzThchuuXxbZ+QZ/1y2xkzErmWeDWIyvd2CQH/yxmtXnzuGykpxxj4/VQjgNDlHwYmUDS+faWJRvpSQvnX6Xm9opZnJE25n5hsgHBxFhbXEWW49pxlI4+NZVmopF+VZcbjOpzLxX9zqw21JZXpg5pTZMhSU5kQ8tn8umKgftPf1jHvvLrbU4Onr5/HXj9xoA7N59uWOtEE6DQ4RVN3Wyu97JLSs9k1wlIV5eIFq21rQyKzmRZXMzonL9tfOzqGs9rUt4h9jp/kGcpwcmXQDnM7TG0gR/zk/3D/LWoWauW5If9SLH29cU0e9y89IYKwGf7h/kfzcf4X0Lsrj4vPF7DQCzU5KwWpJirhBOg0OEvbijgcQEYV35XOBMJke8ZyxtrWll5bmZIdvPd6J8PRZfD0aFhmMSO8AFsiA3jcQEmXDG0tuHmzk9MMgNURxS8lk6N4Nl82w8U1E/ambcz987TnNnH1+4btGEzh2LhXAaHCLI7Tb8urKBy0tzh9IC01KTmJc5K64npZ2nB9jv6GBtceRSWIdbXGDDmpqk8w4h5vuDNdVhpdSkRIqzZ0+457CpykHGrOSoDFcG8tHVRew/2RFwJeDuPhf/99YRLi3JmfD2uLFYCKfBIYLeO9rCSWcvH15x9uJbJfb0uE5n3X68FWOiM9/gk5ggrC6eoxlLIeabJJ3qsBJMfI2lgUE3b+xr5JrF9kmn0YbauvJ5pCQFXozv6b8co7W7n89fWzrh88ZiIVxsvOMzxAs7GrCmJnHtsOWGS+M8Y2lLTSvJicKKczKj2o4LF2RT3dTFqa7YGruNZ44QBodSu5Xa1h56+l1BHf/e0RY6el1jVhdHWsbsZG5cls9LOxvoHRgceryzd4DH3z7KVefnseKcORM+b77NQlNnX9B1FJGgwSFCevpd/H7vST5QVoAl+ezVHeM9Y2lrTSvlhZkjvq9I8/VcKnTeIWQczl7SU5NIT53Y9qCBLLJbMQaqgxxC3VTlYFZyIpeVxtZOjx9dXURnr4tX9zqGHnvy3WO09wxMqtcAnjkHl9vQ0j12JlQkaXCIkE1VDnr6B4eylPzFc8ZST7+LPfXOmBgTXjY3g1nJibx3VINDqHh2gJvcshnDDa2xFMSktNtteK2qkSvPz436h47h3rcgm6KsWTzj3SXO2TPAE+8e5boldpbNm1y2XiwWwmlwiJAXdzRQlDWL1eeO7HIu9GYsBfuJKpZU1rbjcpuYCA4pSQmsPDdT5x1C6KRzcjvABXJu1mxSkhKC+hBUWddOU2dfRJfnDlZCgnD7qiL+crSF2pYennj3KJ29Lv5hkr0GOFProMFhhnE4e/lT9Sk+vHxewFztdG/GUjz2HLbUtJIgsCpA0IuGtcXZ7Hd04DwdW4uYxavGjl7ybaHZCzwpMYGFuekcDCL5YlOVg+RE4cpx1iWKlltXFSICj79zhCffreEDFxSwuMA26fP5AnAsFcJpcIiA3+xswG3gwwGGlHziNWNpa00LS+basFqSo90UwDPvYIwng2q6Gxh08+y2OgYGJ74kRTAG3Yamzj7yM0IzrATejKVxhpWMMby618HF5+Vgi5Gfq+HmZs7ispJcfv5eLT0DgzxwTcmUzpebnopIbC2+p8EhzIwxvLCjnpXnZDJ/jN3R4jFjqc81SGVte1TrG4ZbcU4myYkyI+odNu45yUMv7OYP+5vCcv6Wrj4G3WbKNQ7+Su1WHB29OHtG79kdcHRS29oTE4VvY/nomiIAbi6fOzRvOFlJiQnkpMdWOqsGhzCrOtHBocaugBPR/hbGUcaSMYbqpk5++NZR+lzumJhv8LEkJ1JeODPmHd462AzArvr2sJw/VNXR/hble/d2aBq99/DqXgcicM3i2ElhDeTaJXYeuKaEh28MzZ7WsVYIN/X8NDWmF3c0kJKYwAfLAu8f61Pql7E0Vg8jGtxuwwFHJ1trWthS08rWmtahlLtzsmZz0YLY6TmAZ2jp8beP0tPvYnbK9PwRd7sNbx3yBoe69rBc46QzdDUOPkNrLDk6R60i3lTlYM25WZPeXChSkhMTeOCayU9CD2e3pVLfFjtrg03P35wY4Rp08/KuBq5enEfm7JQxj/XPWLp+aSRaNzrXoJt9JzvYcrSVLTWtbDvWOjTBOy9zFpcvyuV987NZOz+Lc7NnR22N/dGsnZ/F/24+QmVtO5csDG7xs3iz94STlu5+ctJT2FPvxO02IV+Ybqg6OoQ9h3mZs0hLSRw1+eJ4SzcHHJ186YNLQnbNeGG3Wdh+vC3azRiiwSGM3jl8ilNd/SOWywgkmhlLA4Nudtc72VLTwtaaViqOtdHV56liLc6ezQ1L87lwQRZr52dROCdym7tP1qpz55Agnkyq6RocNh9sRgQ++f4FfPPVA9S0dHNebnpIr+Fw9pKUIGSnh+4TvIhQmm8dtdZhU5WnsOy6JbE9pBQOdpuFtp4B+lyDpCZFv7ZDg0MYvbCjnjmzk7liUXDpeCX2dA5HMGPp2KluvvSbvVQca+O0dymAkrx0bl4+lwsXZHPh/KyQjjdHitWSzNK5GWytmb77O2w+2ETZvAyuPD+Xb756gF117aEPDh295FlTQ76z3yK7lU1VDowxI3qdr+51sGyejaKs2P8QEmq+HlpTR19MfP8aHMLEeXqA1/Y1cueaoqCXsS7JS+cvR1oYdJuIbLX5m50neLf6FPdcVMyF87NYMz+LnBB+SoymtfOz+Pl7x2PmU1gotff0s7OunQ1XLqQkz8rslMSz9ggJlcaOXuwhnG/wKbVb+dW2Opq7+siznjl/Y0cvO2rb+cIUisniWZ5fIVwsBAfNVgqT3+85Sb/LPaFf2BK7lb4IZixV1rVRmmflK+uWcuMFBdMmMIAnOPS53Oypd0a7KSH3zuFTuA1cviiPxARh2dyMsGQsOZxT3wEukEXeZTQOOc7uJb+2rxEg5lNYwyXWCuE0OITJizsaOC83jbLC4Nda8WVyRGLjH2MMlbXtUV9JNVzWejNhpmO9w+aDzWTOTmZ5USYAZYUZVJ3omNT+zGNxhGDv6EBKR1lLbNNeBwty0oaSM2aa/KH1lWKjEC6o4CAiN4jIQRGpFpGHAzy/XkSaRWSn9+u+Yc/bRKReRL7vvW/1O3aniJwSkf8J5lzxoK61h63HWrllZeGEMnl8vxSR2Pin5lQ3ztMD0zY4zElLYZHdOu2Cgy+F9dKS3KGhx/KiTPpd7pAmM3T2DtDdPxjSNFafnPQUstJSzmpve08/7x1t4fpl+TGX/RYpGbOSSUlKiJn1lcadcxCRROAHwLVAPbBNRF42xuwbdugzxpgNo5zma8DbvjvGmE5gud81tgMvBnmumPdr7x6zHwoiS8lfJDOWKmvbASa19ny8WDs/ixd31OMadJMUI5vFTNW+kx2c6urjCr9lrMsLMwFPMdxkVwUdzvcHqiAMwUFEKLWnn7Ur3B/2N+FyG26IwYX2IkVEPIVwMRIcgvmNWQtUG2OOGmP6gV8BNwd7ARFZBdiB10Z5vhTIA94J9pyxzBjDizvquWhBNvMyJ75gWaQylirr2rCmJrEwxBkusWTt/Cy6+wfZd3Lklo7xavNBz1IZ/nscFGXNYs7s5JAWwzmcnqGNcGWrLbJ71ljy7cW8qcpBQYZlQsOw05Hdlhoze0kHExzmAf574tV7HxvuVhHZLSLPi0gRgIgkAN8CHhzj/Hfg6Sn4Lyo04lzDicinRKRCRCqam5uD+DYiY0dtO8daerhl5cR6DT4leekRWWOpsrad8qLMkBdOxRLfsh7TaSmNzQebuWBexlnVwyJCWWEmu0M4+e4IQwGcv9J8K939gzS0n6an38Vbh5q5funMHVLysXt3hIsFoeprvwIUG2PKgNeBp72PfxbYaIypH+O1dwC/DOJcZzHGPG6MWW2MWZ2bGzs7Rb24ox5LcgI3XjD2chmj8WUs1YUxY6mn38UBR+e0nW/wsdssFGfPnjbzDs6eAXbUtnHFopE/7+WFGRxq7Ax6C87xhHLv6EAW+U1Kv3WwmT6Xm+tiaDvQaLHbLDicvZz9WTk6ggkODYD/p/dC72NDjDEtxhhfuHsCWOW9fRGwQUSOAf8F3C0i3/C9TkTKgSRjzPYgzhXz+lyD/Hb3SW5Ymj/pbRVLvJPS4Zx32FPvZNBtpn1wAE/vYdux1pjam3ey3qlu9qSwBtg2s6wwE7fxLPQYCiedp8mYlRy2XdhKhtZY6mJTlYM5s5OHMsxmsnybhdMDg3T0hibIT0UwwWEbUCIi80UkBc8n/Zf9DxAR/4/J64D9AMaYu4wx5xhjivEMLf3UGOOf7XQnZ/caRj1XPHjzQBPO0wNj7tswHt8vTTgzliq9Y9O+iczpbO38bNp7BiKSARZubx1sxmZJGkph9VdW5BmrD9W8g8PZF5bJaJ+MWckUZFjYe8LJHw40cc1i+7RJGpgKXyFcUwxMSo/78dYY4xKRDcAmIBF40hhTJSKPAhXGmJeB+0VkHeACWoH1QV7/duCmYY9N9lxR98KOBvKsqVxy3uRXKfVlLIWz1qGyto1zs2eHdM2cWHXh0LxDy1DxVTwyxpvCWpob8I9ontXC3AwLu0I07+DZOzq8S6eU2q28VuVgYNDM2MK34XxzPI6O3invETFVQY19GGM2AhuHPfZlv9uPAI+Mc46ngKeGPbYgwHHjnisWtXb38+aBJu59//wpfwJamBe+XeGMMeyobZ9SAIsnhXNmUZBhYUtNKx+/qDjazZm0fSc7aOo8O4V1OM+kdHtIrufo6GXJFLa9DMaifCtvHWomLSVx2i6QOFG+OZ5YKITTflyIvLLrBC63mXSWkr9Se/gylk44e2nu7JvW9Q3+RIS187PYWtMaE5N8k7XZu7HP5QEmo33KizI53tJDm3evjckaGHRzqqsvLOsq+fNVSl9xfl7Y5jbijX2oSjr6w0oaHELkxR31LCmwcX7+1D9thTNjqbLWs178TJiM9lk7P4umzj6Ot8T+LnujeetgM0vn2s5aqG64cm+NwO6GqQ0tNXX2YUz40lh9fO39q7K5Yb1OPLEkJ5IxK1mDw3RR3dTFrnpnSHoNEN6MpcradlKTEkISxOLFhXFe7+A8PcD2UVJY/S3zBYcpTko7hnaAC++cVIndyrv/dKXONwwTK4VwGhxC4NeV9SQIrFsemk9A4cxYqqxt44J5GUEvIz4dnJebTnZaStzWO/yp+hSDbjPuviA2SzLn5aZNeYXWMzvATbzCf6LiYfOoSLPbLDTGQCHczPkLESZut+HXOxq4rDR3zC7/RKSnJjE3wxLyjKU+1yB7T3TMqCElODPvsCVON//ZfLAJqyWJFQFSWIcrL8xkV71zSvMrjjDsHa2CZ7dZaNSeQ/x7r6aFE87ekG+0UmK3hjxjaf/JTvpd7hkzGe1v7fws6ttO09AeOxu4B2MohbUkJ6gsuLLCDJo7+6a0J0BjRy8pSQnMmZ086XOoycu3WWju6gv7Ejrj0eAwRS/uaMCamhTyPW/DkbE0EyejfXzrLG2Ls6GlA45OGjv6uKI0uK1my729i6kUwzk6erHbUmf8OkfRYrelMug2tHRFd2hJg8MU9PS7+P2ek9x0QUHIU/FK8kKfsVRZ206+zUJBRvjHkmPN+fk2rJakuJt3CCaF1d/iAhtJCTKlYriTYdoBTgXH7lcIF00aHKbg+e31dPcP8uEQZSn5K7GHPmNpZ9303fltPIkJwpriLLbG2bzD5oNNLC6wBV2tbElO5PwC65SK4SJRHa1GFyuFcBocJmlrTStf++0+Lj4vOywLhoU6Y+lUVx+1rT0zNjiAZ2jpSHM3p6LcXQ9WZ+8A24+Pn8I6XHlhJrvrnJNabNAYg8PZG9Z1ldTYtOcQx46d6uZvf1ZB0ZzZ/N9dq8KyJ0KoM5Z2zoCd38YTb/MOf6o+hcttxlwyI5Dywkw6+1zUtHRP+JrO0wP0udzac4iinPRUEiT6i+9pcJggZ88A9z61DQM8uX4NGWHM6CixW0PWc6isayMpQVg2d+butLVsbgazkhPjZt5h88FmrKlJrDx3YgHdNyk9maElR5j3cVDjS0wQcq3RL4TT4DAB/S43n/75duraevjhX6+iOCctrNcryUunuik0GUuVte0sLrAxK2XmrmGTkpTAynMz46JS2hjD5oPNvL8kh+QJLuS4MC+d2SmJ7Kqb+KT0UI2D9hyiKj8GCuE0OATJGMOXXtrLX4628I1byrhwQfhXNS0N0RpLg27Drhk8Ge1vbXE2+x0dOE8PRLspYzrU2IWjozfgxj7jSfT2ECdTKe0LDjqsFF15MVAIp8EhSD98+yjPVNTx91ct5NZVoS14G40vY2mqQ0uHmzrp7h/U4IBn3sEY2H48tnsPmw82AcGnsA5XXpRB1YkOBgbdE3qdb1hJg0N05dssOiEdD17de5JvvnqAD5QV8A/XlEbsugtDtABfpW8yumjmTkb7rDgnk+REifl5h80Hmzk/3zrpmpSywkz6XW4OOib2s9PY0UtOesqMWnsrFtltqThPD9A7MBi1NuhPwDh217fzwDM7KS/M5FsfKQ9LZtJorJbkkGQsVda2MWd2Mudm6yJnluREygtje96hq89FxfHWSfca4MwWsBMdWnI4tcYhFsTCvg4aHMZwov009z1dQXZaKj+6e3VUNiRZGIKMpcradlacM0eXQ/C6cEEWe+qd9PRPfhN3Z88A/7ZxP+//5h+HliUJlT9Vn2Jg0AS9ZEYgRVmzmDM7md0TnJR2dPTpZHQMiIVCOA0Oo+juc/HJpyvo6R/kyfVryLVGZ7/l0ilmLDlPD3C4qSuoFT1nirXzs3G5DTuOt0/4tb0Dg/zo7aNc9p9v8qN3jtJxeoDP/mJHSNfB2XywmfTUJFYXT34YUEQoK8ycRM/hdNh3gFPji4VCOA0OAQy6Dff/spKDjg6+/7EVUd2Y3pexVN82uYwlX677TC5+G27VuXNIECa0lIbbbXipsoGrv/UWX9+4n+VFmWy8/1J+cd/7aOnu54FndoYk5dgYw1sHm7hkYfaEU1iHKy/M4FBjZ9A9pN6BQdp6BrTnEAN8wSGahXAaHAL4+u/284cDTXx13dJxN1gJt4VDayxNbmipsrYdESgrmrnFb8OlpyaxbF5G0JPSf64+xbofvMsDz+wkc3YyP//khTx971oWF9i4oDCDR9ct5Z3Dp/jOG4em3LbDTV2ccPaG5OeuvCgTt4GqEx1BHd/kHcLQArjos1mSsCQnRLUQToPDMD977zhP/qmG9RcX8/GLiqPdnClvGVpZ20ZJXjo2i67N729tcRaVde30uUbPBjng6GD9T7bysSe20NY9wP98dDmvbHg/7y/JOeu4j64p4iOrCvnuH6t580DTlNr1lm8V1knUNwxX5puUDnL57qHqaO05RJ2IRL0QToODn7cONfOVl6u46vw8vvTBJdFuDnAmY6l6EpPSxhgq69o1hTWAtfOz6He52R1gaeuTztP843O7uPE777DjeBv/fNP5/OELl/OhFfMCZquJCF/70DIWF9h44JmdUypa3HyoiVJ7OnMzp76seq41lbkZlqCX79alM2JLtAvhNDh4HWrsZMMvdlCSl85371xBYgRTVsez0G6dVM/hWEsP7T0DWvwWwBrvSrr+Ka0dvQP8x6sHuOI/N/ObnSe47/3zefuhK/nUZeeNm6lmSU7k/+5aidsYPvuLHZPKT+/uc7Gtpi2kQ5nlRZlBr7HUqNXRMSXahXAaHIDmzj4+8ZNtWFIS+fH6NaSnJkW7SWeZbMbSmZ3ftOcw3Jy0FBbZrWypaaXf5eYnf6rh8v94k//dfIQbl+Xzhy9czhc/sITM2SlBn7M4J41vfaScPQ1OvvrKvgm36c9HWugfdE94FdaxlBVmcrylh7bu/nGPPensZVZyIjZLbP38z1R2WyqNHb1T2g98KmZ8cOgdGORTP6ugpbuPJ+5ezbwQdOdDrcSePqmMpcradtJTk4YqrdXZ1s7PYltNK9d++y2++so+FhfYeGXD+/mfO1ZQlDW5gsHrlubzmSvO45dba3muom5Cr918sIm0lERWh3B/kPJCTyLC7obxh5YaO3rJz7BoPUyMsNss9LncUVsHbEYHB7fb8OBzu6isbefbty8fWuo41vg2/ploxlJlXRvlRRkxNUQWSy5ZmM3pgUEsSYn85BNr+MV9F3JB4dSzur5wbSkXLcjmX17ay74gM4V8q7BevDAnpEtXLCvMQAR2BzEp7ejQ7UFjSbQL4WZ0cHjs7SP8dvdJ/umG87nxgoJoN2dUk8lYOt0/yP6TnSyP0YAXC65fms9v/u4SNn7uUq5clBeyT8xJiQl8984VZMxK5jO/2B7UJ78jzV00tJ+e8K5v47FZklmQkxZUMZzD2auT0TEk2oVwQQUHEblBRA6KSLWIPBzg+fUi0iwiO71f9w173iYi9SLyfe99q9+xO0XklIj8j/e5VBF5xnutLSJSPPVvM7C/KpvLP1xTyqcvXxCuS4SE1ZJMwQQzlvY0OBl0G81UGoOIUF6UGZaeVa41lf+9ayUNbad58Lld444bb/amsIajrqa8MJNd9c4x2+B2G5o6dV2lWJIf5fWVxg0OIpII/AC4EVgC3CkigfI8nzHGLPd+PTHsua8Bb/vuGGM6/Y5dDhwHXvQ+/UmgzRizEPg28M2JflPBKsqazeeuKYmLMdaSCWYs+Sajl2umUtSsLs7ikZsW8/q+Rn749tExj33rUDMleelhmfMqL8qkubNvzE+grT39DAwa8m3RWSZGjeRbsida6azB9BzWAtXGmKPGmH7gV8DNwV5ARFYBduC1UZ4vBfKAd7wP3Qw87b39PHC1xMNf7zCbaMZSZW0752TNJiddf9mj6d5LivnABQX8x6sH+MuRwMt19PS72HK0NSSFb4GUeedRxiqGG9oBToeVYoYlOZE5s5Np7Izd4DAP8E+7qPc+NtytIrJbRJ4XkSIAEUkAvgU8OMb578DT6/D91Ru6njHGBTiBEduuicinRKRCRCqam5uD+Dbi20Qzlirr2rS+IQaICN+8rYzinDT+/peVAYcI/uJLYQ3TUi2LC2wkJciYxXC6A1xsstssOJzxPSH9ClBsjCkDXufMJ//PAhuNMfVjvPYO4JcTvaAx5nFjzGpjzOrc3PB84oolE8lYOuk8TWNHn67EGiPSU5P44V+voqffxYb/t2PE7mybDzYzOyWRNfPDMz9kSU5kcYFtzGI435DTZDcXUuFht1lid84BaACK/O4Xeh8bYoxpMcb4wtsTwCrv7YuADSJyDPgv4G4R+YbvdSJSDiQZY7YHup6IJAEZQPDLZ05TvlqFw03jzzsM7fymxW8xo8Ru5d9vuYBtx9r45u8PDD1ujGHzoSYuPi+b1KTw7RdSVpjB7jon7lGGJRs7ekkQyEkPvuhPhZ+vEC4aggkO24ASEZkvIil4Pum/7H+AiPjnga4D9gMYY+4yxpxjjCnGM7T0U2OMf7bTnYzsNbwM3OO9fRvwRxOtEsEYYvNmLB0OoudQWdtGSlICiwtsEWiZCtbNy+dxz0Xn8sS7NWzccxKAo6e6qWs9zeVhXv23vDCTzj4XNS3dAZ93OHvJtaaSNMVlwlVo5dssnOrqwzXBvcBDYdw6eWOMS0Q2AJuAROBJY0yViDwKVBhjXgbuF5F1gAtoBdYHef3bgZuGPfZj4GciUu091x1BnmvaCzZjqbK2nQvmZeg+wDHoix9Ywq56J//43C4W5VvPpLCGaTLax1fgubu+nfNyR1bMawFcbLJnWHAbONXVH/FkgaAWUTHGbAQ2Dnvsy363HwEeGeccTwFPDXtsRIGBMaYX+Egw7ZppSvLS2XK0hUG3GTU3v9/lZk+Dk4+/79wIt04FIyUpgf+9ayUf/N67fObn28mclcJ5uWmTXq4jWAvz0pmdksiuOicfXlE44nmHs5f5OWlhbYOaOLv1TCFcpIODfrSMI6VBZCwdcHTQ53LrfEMMm5s5i+/esYLDTV1sPdYakQ2lEhOEZXMzRq2UdnT0UqBprDHnzBIakZ930OAQR3wZS2PNO5yZjM6MQIvUZL2/JIfPX1MKwNWLI7PbYHlRBlUnOkZkS/X0u+jsdene0TEoz1uUqMFBjcmXsXRojIylyto27LZU/RQYBzZctZBXH7iUi8/LGf/gECgrzKTf5eag4+yfn6ECOJ1ziDk5aakkJogGBzW2YDKWfDu/aVF57BMRzs+PXEZZuW/b0GFDS7o9aOxKSBDyrKlRKYTT4BBnFualj1rr0NLVx/GWHh1SUgEVZc1izuxkdtedXSk9VB2tvc2YFK1COA0OcabUbqW6qStgMdNO79o5OhmtAhERygoztecQZ6JVCKfBIc6U2tPpHXBTFyBjqbK2ncQE4YJ5U9+wRk1P5YUZHGrspKffNfRYo7MXqyWJtBjbHld5RGsvaQ0OcWZh3ugZS5V1bSwusDIrJXzLMKj4Vl6UidtAld8OdVoAF9vsGRY6e11nBfRI0OAQZ0rsgTOWBt2GXXVO3dxHjanMNyntt3y3o6NPl+qOYb5CuEhvF6rBIc74Mpaqh/Ucqpu66Opz6WS0GlOuNZW5GZazlu9udOoOcLEsWoVwGhzi0MK89BE9B9/ObzoZrcZTXpQ5tHy3a9BNU6cOK8Uye5QK4TQ4xKFAGUuVte1kzk6mODu8a/So+FdWmMnxlh7auvs51dWP22gaayyzR2kvaQ0Ocagkz5OxVN92euixyro2VhRlavGbGle5d9vQ3Q3OM5v8aM8hZqWnJjE7JTHihXAaHOLQmV3hPENLHb0DHG7q0iElFZRlhRmIwO66dt07Og6ICPk2S8T3ktbgEIeGZyztrnNijC62p4JjsySzICeNXfXtQ0MVOiEd2/JsqTQ6NTiocdgsyeTbzmQsVda2IXJmQxelxlNemMmueicnnb0kJwrZabo9aCyLRiGcBoc4VWI/k7FUWdfOwtx0bJbkKLdKxYvyokyaO/vYWddGntVCwiibR6nYYM+w0NTRRyR3TNbgEKd8GUuDbkNlbZsOKakJKfNOSm+tadX5hjhgt1roH3TT1jMQsWtqcIhTvoylPx85RVvPgE5GqwlZXGAjKUFwG11wLx5EoxBOg0Oc8mUsPbOtDtDJaDUxluREFhd49pLQyejY5yuEi+S8gwaHOOXbFe61qkbSUhIp8S7Ip1SwfENL+RmpUW6JGo8vgDdpcFDjyZjlyVjqH3RTVphJok4oqgny7QynPYfYl+ddfC+ShXAaHOKYr95Bh5TUZFxWmkt5USarztX5qliXkpRAdlpKRAvhNDjEMd9Qkk5Gq8nIz7Dwm7+7hMI5uh5XPMizWSJaCKfBIY6tnZ9FemqSfvJTagbIt6VGdEJa9wWMY9cvtXPV+deSkqQxXqnpLj/Dwp6GjvEPDBH9qxLHREQDg1IzRJ7VQkt3HwOD7ohcL6i/LCJyg4gcFJFqEXk4wPPrRaRZRHZ6v+4b9rxNROpF5Pt+j6WIyOMickhEDojIrcGcSymlZqL8DAvGQHNnZDKWxh1WEpFE4AfAtUA9sE1EXjbG7Bt26DPGmA2jnOZrwNvDHvsi0GSMKRWRBCAryHMppdSM418INzdzVtivF0zPYS1QbYw5aozpB34F3BzsBURkFWAHXhv21L3AvwMYY9zGmFPBnlMppWaaSBfCBRMc5gF1fvfrvY8Nd6uI7BaR50WkCMDbI/gW8KD/gSKS6b35NRHZISLPiYh9rHMppdRM5gsOjgils4ZqNvMVoNgYUwa8DjztffyzwEZjTP2w45OAQuDPxpiVwF+A/xrnXGcRkU+JSIWIVDQ3N4fo21BKqdiUNTuF5EShMUJzDsEEhwbA/9N7ofexIcaYFmOMr8VPAKu8ty8CNojIMTx//O8WkW8ALUAP8KL3uOeAleOc6yzGmMeNMauNMatzc3OD+DaUUip+JSQIedbIFcIFExy2ASUiMl9EUoA7gJf9DxCRAr+764D9AMaYu4wx5xhjivEMLf3UGPOw8exY8Qpwhfc1VwP7xjqXUkrNdPYIFsKNm61kjHGJyAZgE5AIPGmMqRKRR4EKY8zLwP0isg5wAa3A+iCu/U/Az0Tkf4Bm4BPexydzLqWUmvbsNguHGjsjci2J5LZz4bJ69WpTUVER7WYopVRYfeXlKp7fXs/er14fkvOJyHZjzOpAz2l5rVJKxYn8DAtdfS66+lxhv5YGB6WUihO+QrhIbBeqwUEppeKEr9ZBg4NSSqkhGhyUUkqNcCY4hL8QToODUkrFifTUJNJTkyKyhIYGB6WUiiN2W6oOKymllDqb3WbR4KCUUups+TaLzjkopZQ6mz3DQlNnL253eFe30OCglFJxxG5NZWDQ0NrTH9braHBQSqk4kp8RmVoHDQ5KKRVH8iJUCKfBQSml4kh+hArhNDgopVQcybWmIhL+vaQ1OCilVBxJTkwgOy38hXAaHJRSKs5Eokpag4NSSsWZfJsFh845KKWU8mfPsNCkPQellFL+7FYLLd399LkGw3YNDQ5KKRVn8jM824U2d4ZvaEmDg1JKxZlIFMJpcFBKqTgTiUI4DQ5KKRVnfNuFhrMQToODUkrFmTmzk0lJTNBhJaWUUmeICHlhLoTT4KCUUnHIUwinwUEppZQfTyFclCekReQGETkoItUi8nCA59eLSLOI7PR+3TfseZuI1IvI9/0eSxGRx0XkkIgcEJFbvY+nisgz3mttEZHiKX6PSik17ditnp6DMeHZLjRpvANEJBH4AXAtUA9sE5GXjTH7hh36jDFmwyin+Rrw9rDHvgg0GWNKRSQByPI+/kmgzRizUETuAL4JfDS4b0cppWaG/IxUevoH6epzYbUkh/z8wfQc1gLVxpijxph+4FfAzcFeQERWAXbgtWFP3Qv8O4Axxm2MOeV9/Gbgae/t54GrRUSCvZ5SSs0E9jAXwgUTHOYBdX73672PDXeriOwWkedFpAjA2yP4FvCg/4Eikum9+TUR2SEiz4mIffj1jDEuwAlkD7+YiHxKRCpEpKK5uTmIb0MppaYPe5gL4UI1If0KUGyMKQNe58wn/88CG40x9cOOTwIKgT8bY1YCfwH+ayIXNMY8boxZbYxZnZubO7XWK6VUnAl3Idy4cw5AA1Dkd7/Q+9gQY0yL390ngP/w3r4IuFREPgukAyki0gU8AvQAL3qPew7PXIP/9epFJAnIAPzPr5RSM16+zcJ1S+zkWFPDcv5ggsM2oERE5uP5w30H8DH/A0SkwBhz0nt3HbAfwBhzl98x64HVxpiHvfdfAa4A/ghcDfgmuF8G7sHTm7gN+KMJ13S8UkrFqVkpiTx+9+qwnX/c4GCMcYnIBmATkAg8aYypEpFHgQpjzMvA/SKyDnABrcD6IK79T8DPROR/gGbgE97Hf+x9vNp7rjsm9i0ppZSaKpkOH8pXr15tKioqot0MpZSKKyKy3RgTsPuhFdJKKaVG0OCglFJqBA0OSimlRtDgoJRSagQNDkoppUbQ4KCUUmqEaZHKKiLNwPFJvjwHODXuUdGj7Zsabd/UxXobtX2Td64xJuD6Q9MiOEyFiFSMlucbC7R9U6Ptm7pYb6O2Lzx0WEkppdQIGhyUUkqNoMEBHo92A8ah7Zsabd/UxXobtX1hMOPnHJRSSo2kPQellFIjaHBQSik1wowJDiJyg4gcFJFqEXk4wPOpIvKM9/ktIlIcwbYVicibIrJPRKpE5HMBjrlCRJwistP79eVItc97/WMissd77RHro4vHd73v324RWRnBti3ye192ikiHiDww7JiIv38i8qSINInIXr/HskTkdRE57P13ziivvcd7zGERuSdCbftPETng/f/7td9e78NfO+bPQpjb+BURafD7f7xplNeO+fsexvY949e2YyKyc5TXRuQ9nBJjzLT/wrNJ0RFgAZAC7AKWDDvms8Bj3tt3AM9EsH0FwErvbStwKED7rgB+G8X38BiQM8bzNwG/BwR4H7Aliv/XDjzFPVF9/4DLgJXAXr/H/gN42Hv7YeCbAV6XBRz1/jvHe3tOBNp2HZDkvf3NQG0L5mchzG38CvBgED8DY/6+h6t9w57/FvDlaL6HU/maKT2HtUC1MeaoMaYf+BVw87Bjbgae9t5+HrhaRCQSjTPGnDTG7PDe7sSzzeq8SFw7hG4Gfmo83gMyRaQgCu24GjhijJlsxXzIGGPexrOboT//n7OngQ8FeOn1wOvGmFZjTBvwOnBDuNtmjHnNGOPy3n0Pz37xUTPK+xeMYH7fp2ys9nn/dtwO/DLU142UmRIc5gF1fvfrGfnHd+gY7y+IE8iOSOv8eIezVgBbAjx9kYjsEpHfi8jSyLYMA7wmIttF5FMBng/mPY6EOxj9FzKa75+P3ZzZb90B2AMcEwvv5b14eoKBjPezEG4bvENfT44yLBcL79+lQKMx5vAoz0f7PRzXTAkOcUFE0oEXgAeMMR3Dnt6BZ6ikHPge8FKEm/d+Y8xK4Ebg70Tksghff1wikgKsA54L8HS0378RjGd8IeZyyUXki3j2g//FKIdE82fh/4DzgOXASTxDN7HoTsbuNcT879NMCQ4NQJHf/ULvYwGPEZEkIANoiUjrPNdMxhMYfmGMeXH488aYDmNMl/f2RiBZRHIi1T5jTIP33ybg13i67v6CeY/D7UZghzGmcfgT0X7//DT6htu8/zYFOCZq76WIrAc+CNzlDV4jBPGzEDbGmEZjzKAxxg38aJRrR/Vn0fv34xbgmdGOieZ7GKyZEhy2ASUiMt/76fIO4OVhx7wM+LJCbgP+ONovR6h5xyd/DOw3xvz3KMfk++ZARGQtnv+7iAQvEUkTEavvNp6Jy73DDnsZuNubtfQ+wOk3fBIpo35ai+b7N4z/z9k9wG8CHLMJuE5E5niHTa7zPhZWInID8BCwzhjTM8oxwfwshLON/vNYHx7l2sH8vofTNcABY0x9oCej/R4GLdoz4pH6wpNNcwhPFsMXvY89iucXAcCCZziiGtgKLIhg296PZ3hhN7DT+3UT8Gng095jNgBVeDIv3gMujmD7Fnivu8vbBt/7598+AX7gfX/3AKsj/P+bhuePfYbfY1F9//AEqpPAAJ5x70/imcf6A3AYeAPI8h67GnjC77X3en8Wq4FPRKht1XjG6n0/g77svbnAxrF+FiL4/v3M+/O1G88f/ILhbfTeH/H7Hon2eR9/yvdz53dsVN7DqXzp8hlKKaVGmCnDSkoppSZAg4NSSqkRNDgopZQaQYODUkqpETQ4KKWUGkGDg1JKqRE0OCillBrh/wf6KkIYta9hLgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.title(\"trainloss\")\n",
    "plt.plot(np.arange(len(losses)), losses)\n",
    "plt.legend([\"Train Loss\"], loc=\"upper right\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
